package com.ruoyi.phd.listener;


import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.ruoyi.phd.domain.PhdInformation;
import com.ruoyi.phd.service.IPhdInformationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * Excel读取监听器：逐行读取Excel数据并批量插入数据库
 */
public class PhdExcelListener implements ReadListener<PhdInformation> {
    // 日志打印
    private static final Logger log = LoggerFactory.getLogger(PhdExcelListener.class);
    // 批量插入阈值：每积累100条数据插入一次，避免频繁操作数据库
    private static final int BATCH_SIZE = 100;
    // 临时存储读取到的数据
    private List<PhdInformation> dataList = new ArrayList<>(BATCH_SIZE);
    // 服务层对象（通过构造方法注入）
    private IPhdInformationService phdInformationService;

    // 构造方法：接收服务层对象
    public PhdExcelListener(IPhdInformationService phdInformationService) {
        this.phdInformationService = phdInformationService;
    }

    /**
     * 每读取Excel的一行数据，就会调用该方法
     * @param data 读取到的一行数据（已自动映射到PhdInformation实体）
     * @param context 读取上下文
     */
    @Override
    public void invoke(PhdInformation data, AnalysisContext context) {
        log.info("读取到Excel数据：{}", data);
        // 将读取到的数据加入临时列表
        dataList.add(data);
        // 当临时列表达到批量阈值时，执行批量插入
        if (dataList.size() >= BATCH_SIZE) {
            batchInsert();
            // 清空列表，准备接收下一批数据
            dataList.clear();
        }
    }

    /**
     * Excel全部读取完成后，调用该方法（处理剩余不足批量阈值的数据）
     * @param context 读取上下文
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 插入剩余数据
        if (!dataList.isEmpty()) {
            batchInsert();
            log.info("Excel读取完成，剩余数据插入成功");
        }
    }

    /**
     * 批量插入数据库（调用服务层方法）
     */
    private void batchInsert() {
        try {
            phdInformationService.batchInsertPhdInformation(dataList);
            log.info("批量插入{}条博士信息成功", dataList.size());
        } catch (Exception e) {
            log.error("批量插入博士信息失败", e);
            // 若需要抛异常给前端，可在此处抛出RuntimeException
            throw new RuntimeException("Excel数据插入失败：" + e.getMessage());
        }
    }
}